package org.example.domain.search.service;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.example.domain.cache.CacheKeyGenerator;
import org.example.domain.cache.CacheService;
import org.example.domain.config.PanSouProperties;
import org.example.domain.plugin.service.AsyncSearchPlugin;
import org.example.domain.plugin.service.PluginManager;
import org.example.types.enums.SourceType;
import org.example.types.model.*;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Scheduler;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 搜索服务
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class SearchService {

    private final PluginManager pluginManager;
    private final CacheService cacheService;
    private final CacheKeyGenerator cacheKeyGenerator;
    private final PanSouProperties panSouProperties;

    @Qualifier("searchScheduler")
    private final Scheduler searchScheduler;

    /**
     * 执行搜索
     */
    public Mono<SearchResponse> search(SearchRequest request) {
        // 生成缓存键
        String cacheKey = cacheKeyGenerator.generateSearchCacheKey(request);

        // 检查缓存
        if (!request.isForceRefresh()) {
            return cacheService.get(cacheKey, SearchResponse.class)
                    .switchIfEmpty(doSearch(request, cacheKey));
        }

        return doSearch(request, cacheKey);
    }

    /**
     * 执行实际搜索
     */
    private Mono<SearchResponse> doSearch(SearchRequest request, String cacheKey) {
        SourceType sourceType = SourceType.fromCode(request.getSourceType());

        // 创建搜索上下文
        SearchContext context = SearchContext.builder()
                .mainCacheKey(cacheKey)
                .keyword(request.getKeyword())
                .requestId(UUID.randomUUID().toString())
                .timeoutMs(panSouProperties.getAsync().getResponseTimeout().toMillis())
                .build();

        // 并行执行不同来源的搜索
        Mono<List<SearchResult>> tgSearch = searchTelegram(request, context);
        Mono<List<SearchResult>> pluginSearch = searchPlugins(request, context);

        return Mono.zip(tgSearch, pluginSearch)
                .map(tuple -> {
                    List<SearchResult> allResults = new ArrayList<>();

                    // 根据来源类型决定包含哪些结果
                    if (sourceType == SourceType.ALL || sourceType == SourceType.TG) {
                        allResults.addAll(tuple.getT1());
                    }
                    if (sourceType == SourceType.ALL || sourceType == SourceType.PLUGIN) {
                        allResults.addAll(tuple.getT2());
                    }

                    return processResults(allResults, request);
                })
                .doOnNext(response -> {
                    // 异步缓存结果
                    cacheService.set(cacheKey, response, panSouProperties.getCache().getTtl())
                            .subscribeOn(searchScheduler)
                            .subscribe();
                })
                .subscribeOn(searchScheduler);
    }

    /**
     * 搜索Telegram频道
     */
    private Mono<List<SearchResult>> searchTelegram(SearchRequest request, SearchContext context) {
        // 基础实现：根据关键词和频道生成模拟结果
        // 实际生产环境需要调用Telegram API

        final List<String> effectiveChannels = request.getChannels() != null && !request.getChannels().isEmpty()
                ? request.getChannels()
                : panSouProperties.getDefaultChannels();

        return Mono.fromCallable(() -> createTelegramResults(request.getKeyword(), effectiveChannels))
                .subscribeOn(searchScheduler);
    }

    /**
     * 创建Telegram搜索结果
     */
    private List<SearchResult> createTelegramResults(String keyword, List<String> channels) {
        List<SearchResult> results = new ArrayList<>();

        for (String channel : channels) {
            // 为每个频道创建1-2个结果
            results.addAll(createChannelResults(keyword, channel));
        }

        return results;
    }

    /**
     * 为指定频道创建结果
     */
    private List<SearchResult> createChannelResults(String keyword, String channel) {
        List<SearchResult> results = new ArrayList<>();

        // 主要结果
        SearchResult mainResult = SearchResult.builder()
                .uniqueId("tg-" + channel + "-" + keyword.hashCode() + "-1")
                .title("📁 " + keyword + " 完整版")
                .content("来自 @" + channel + " 频道的资源分享")
                .channel(channel)
                .datetime(LocalDateTime.now().minusHours(2))
                .messageId("tg://" + channel + "/123")
                .links(List.of(
                        Link.builder()
                                .type("pan.baidu.com")
                                .url("https://pan.baidu.com/s/tg" + channel.hashCode())
                                .password("tg" + (keyword.hashCode() % 10000))
                                .build()
                ))
                .build();

        results.add(mainResult);

        // 如果关键词较长，添加额外结果
        if (keyword.length() > 2) {
            SearchResult extraResult = SearchResult.builder()
                    .uniqueId("tg-" + channel + "-" + keyword.hashCode() + "-2")
                    .title("🎬 " + keyword + " 高清资源")
                    .content("@" + channel + " 频道推荐，资源质量优质")
                    .channel(channel)
                    .datetime(LocalDateTime.now().minusHours(5))
                    .messageId("tg://" + channel + "/456")
                    .links(List.of(
                            Link.builder()
                                    .type("pan.aliyundrive.com")
                                    .url("https://www.aliyundrive.com/s/tg" + (channel.hashCode() + 1))
                                    .password("")
                                    .build()
                    ))
                    .build();

            results.add(extraResult);
        }

        return results;
    }

    /**
     * 搜索插件
     */
    private Mono<List<SearchResult>> searchPlugins(SearchRequest request, SearchContext context) {
        if (!panSouProperties.getAsync().isPluginEnabled()) {
            return Mono.just(Collections.emptyList());
        }

        List<AsyncSearchPlugin> enabledPlugins = pluginManager.getEnabledPlugins(request.getPlugins());

        if (enabledPlugins.isEmpty()) {
            return Mono.just(Collections.emptyList());
        }

        return Flux.fromIterable(enabledPlugins)
                .flatMap(plugin ->
                        plugin.asyncSearch(request.getKeyword(), context, request.getExt())
                                .map(PluginSearchResult::getResults)
                                .onErrorResume(ex -> {
                                    log.warn("Plugin {} search failed: {}", plugin.getName(), ex.getMessage());
                                    return Mono.just(Collections.emptyList());
                                })
                )
                .collectList()
                .map(resultLists ->
                        resultLists.stream()
                                .flatMap(List::stream)
                                .collect(Collectors.toList())
                );
    }

    /**
     * 处理搜索结果
     */
    private SearchResponse processResults(List<SearchResult> allResults, SearchRequest request) {
        // 1. 去重和排序
        List<SearchResult> uniqueResults = deduplicateResults(allResults);
        sortResults(uniqueResults);

        // 2. 过滤结果
        List<SearchResult> filteredResults = filterResults(uniqueResults, request);

        // 3. 按网盘类型分组
        Map<String, List<MergedLink>> mergedByType = mergeResultsByType(filteredResults, request);

        // 4. 构建响应
        return SearchResponse.builder()
                .total(filteredResults.size())
                .results(filteredResults)
                .mergedByType(mergedByType)
                .build();
    }

    /**
     * 结果去重
     */
    private List<SearchResult> deduplicateResults(List<SearchResult> results) {
        Map<String, SearchResult> uniqueMap = new LinkedHashMap<>();

        for (SearchResult result : results) {
            String key = generateResultKey(result);
            if (!uniqueMap.containsKey(key) || isResultBetter(result, uniqueMap.get(key))) {
                uniqueMap.put(key, result);
            }
        }

        return new ArrayList<>(uniqueMap.values());
    }

    /**
     * 生成结果唯一键
     */
    private String generateResultKey(SearchResult result) {
        if (result.getUniqueId() != null && !result.getUniqueId().isEmpty()) {
            return result.getUniqueId();
        }
        if (result.getMessageId() != null && !result.getMessageId().isEmpty()) {
            return result.getMessageId();
        }
        return String.format("title_%s_%s", result.getTitle(), result.getChannel());
    }

    /**
     * 判断结果是否更好
     */
    private boolean isResultBetter(SearchResult newResult, SearchResult existingResult) {
        // 优先选择有链接的结果
        if (newResult.getLinks() != null && !newResult.getLinks().isEmpty() &&
            (existingResult.getLinks() == null || existingResult.getLinks().isEmpty())) {
            return true;
        }

        // 优先选择有时间的结果
        if (newResult.getDatetime() != null && existingResult.getDatetime() == null) {
            return true;
        }

        // 优先选择更新的结果
        if (newResult.getDatetime() != null && existingResult.getDatetime() != null) {
            return newResult.getDatetime().isAfter(existingResult.getDatetime());
        }

        return false;
    }

    /**
     * 排序结果
     */
    private void sortResults(List<SearchResult> results) {
        results.sort((r1, r2) -> {
            // 按时间倒序
            if (r1.getDatetime() != null && r2.getDatetime() != null) {
                return r2.getDatetime().compareTo(r1.getDatetime());
            }
            if (r1.getDatetime() != null) return -1;
            if (r2.getDatetime() != null) return 1;

            // 按标题排序
            return r1.getTitle().compareTo(r2.getTitle());
        });
    }

    /**
     * 过滤结果
     */
    private List<SearchResult> filterResults(List<SearchResult> results, SearchRequest request) {
        // TODO: 根据request的cloudTypes等参数进行过滤
        return results;
    }

    /**
     * 按网盘类型合并结果
     */
    private Map<String, List<MergedLink>> mergeResultsByType(List<SearchResult> results, SearchRequest request) {
        Map<String, List<MergedLink>> mergedByType = new HashMap<>();

        for (SearchResult result : results) {
            if (result.getLinks() == null) continue;

            for (Link link : result.getLinks()) {
                String type = link.getType();
                if (type == null) type = "others";

                MergedLink mergedLink = MergedLink.builder()
                        .url(link.getUrl())
                        .password(link.getPassword())
                        .note(result.getTitle())
                        .datetime(result.getDatetime())
                        .source(determineSource(result))
                        .images(result.getImages())
                        .build();

                mergedByType.computeIfAbsent(type, k -> new ArrayList<>()).add(mergedLink);
            }
        }

        return mergedByType;
    }

    /**
     * 确定数据来源
     */
    private String determineSource(SearchResult result) {
        if (result.getChannel() != null && !result.getChannel().isEmpty()) {
            return "tg:" + result.getChannel();
        }
        if (result.getUniqueId() != null && result.getUniqueId().contains("-")) {
            String[] parts = result.getUniqueId().split("-", 2);
            return "plugin:" + parts[0];
        }
        return "unknown";
    }
}